<template>
    <div class="three-display three-init">
        <div id="three-canvas" class="three-canvas" ref="three-canvas"></div>
    </div>
</template>

<script>
import {mapActions} from 'vuex'
import Stats from '../../../../node_modules/three/examples/jsm/libs/stats.module'
import {OrbitControls} from '../../../../node_modules/three/examples/jsm/controls/OrbitControls'
import {GUI} from '../../../../node_modules/three/examples/jsm/libs/dat.gui.module'
export default {
  data () {
    return {
      renderer: '', // 渲染器
      scene: '', // 场景
      camera: '', // 相机
      stats: '', // 资源监视器
      lightBox: '',
      helperBox: '',
      objBox: {
        group: ''
      },
      clock: '', // 世界时钟
      orbitControls: '', // 相机控件
      animationFrame: '', // 动画
      gui: '', // 控制台
      guiParam: '' // 控制台参数
    }
  },
  methods: {
    // 初始
    init () {
      this.initRender()
      this.initScene()
      this.initClock()
      this.initCamera()
      this.initObj()
      this.initLight()
      this.initHelper()
      this.initStats()
      this.initOrbitControls()
      this.initGui()
      this.updateRenderer()
    },
    // 初始渲染器
    initRender () {
      this.renderer = new THREE.WebGLRenderer({antialias: true}) // 渲染器
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.renderer.shadowMap.enabled = true // 渲染器阴影渲染
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap // 阴影类型
      this.$refs['three-canvas'].appendChild(this.renderer.domElement)
      this.renderer.setClearColor('rgb(15, 1, 25)')
    },
    // 初始场景
    initScene () {
      this.scene = new THREE.Scene() // 场景
    },
    // 初始世界时钟
    initClock () {
      this.clock = new THREE.Clock() // 世界时钟
    },
    // 光源
    initLight () {
      this.lightBox = {
        ambientLight: new THREE.AmbientLight('rgb(255, 255, 255)'), // 环境光
        directionalLight: new THREE.DirectionalLight('rgb(255, 255, 255)', 1) // 平行光
      }
      this.lightBox.directionalLight.position.set(0, 300, 0)
      this.lightBox.directionalLight.castShadow = true
      // this.scene.add(this.lightBox.ambientLight)
      this.scene.add(this.lightBox.directionalLight)
    },
    // 初始相机
    initCamera () {
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000) // 相机
      this.camera.position.x = 400
      this.camera.position.y = 800
      this.camera.position.z = 400
      this.camera.up.x = 0
      this.camera.up.y = 1
      this.camera.up.z = 0
      this.camera.lookAt(new THREE.Vector3(0, 0, 0))
    },
    // 初始物体
    initObj () {
      // 设置组合
      this.objBox.group = new THREE.Group()

      let geometry = new THREE.BoxBufferGeometry(50, 50, 50)
      // 颜色
      let colorRange = [0, 64, 128, 192, 255]
      // 空间位置
      let positionRange = [-200, -100, 0, 100, 200]

      for (let x = 0; x < positionRange.length; x += 1) {
        for (let y = 0; y < positionRange.length; y += 1) {
          for (let z = 0; z < positionRange.length; z += 1) {
            let material = new THREE.MeshPhongMaterial({color: `rgb(${colorRange[x]}, ${colorRange[y]}, ${colorRange[z]})`, roughness: 0})
            let box = new THREE.Mesh(geometry, material)
            box.castShadow = true
            box.receiveShadow = true
            box.position.set(positionRange[x], positionRange[y], positionRange[z])
            this.objBox.group.add(box)
          }
        }
      }
      this.scene.add(this.objBox.group)
    },
    // 初始辅助
    initHelper () {
      this.helperBox = {
        axesHelper: {helper: new THREE.AxesHelper(10000)}, // 坐标轴
        gridHelper: {helper: new THREE.GridHelper(1500, 30, 'white', 'rgb(150, 150, 150)')}, // 网格
        directionalLightHelper: {helper: new THREE.DirectionalLightHelper(this.lightBox.directionalLight, 200)}
      }
      // this.scene.add(this.helperBox.axesHelper.helper)
      // this.scene.add(this.helperBox.gridHelper.helper)
      this.scene.add(this.helperBox.directionalLightHelper.helper)
    },
    // 初始监视器
    initStats () {
      this.stats = new Stats() // 资源监视器
      this.stats.setMode(0)
      this.stats.domElement.id = 'three-stats'
      this.stats.domElement.style.position = 'absolute'
      this.stats.domElement.style.left = 'unset'
      this.stats.domElement.style.right = '300px'
      this.stats.domElement.style.top = '0px'
      document.body.appendChild(this.stats.domElement)
    },
    // 加载相机插件
    initOrbitControls () {
      this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement)
      this.orbitControls.autoRotate = true
    },
    // 初始控制台
    initGui () {
      this.gui = new GUI({
        name: 'AmbientLight Controller'
      }) // 控制台
      this.guiParam = { // 控制参数
        autoCamera: this.orbitControls.autoRotate,
        color: this.lightBox.directionalLight.color.getHex(),
        intensity: this.lightBox.directionalLight.intensity,
        positionX: this.lightBox.directionalLight.position.x,
        positionY: this.lightBox.directionalLight.position.y,
        positionZ: this.lightBox.directionalLight.position.z
      }
      this.gui
        .add(this.guiParam, 'autoCamera')
        .onChange(data => {
          this.orbitControls.autoRotate = data
        })
      this.gui
        .addColor(this.guiParam, 'color', -500, 500)
        .onChange(data => {
          this.lightBox.directionalLight.color.setHex(data)
          this.helperBox.directionalLightHelper.helper.update()
        })
      this.gui
        .add(this.guiParam, 'intensity', 0, 10)
        .onChange(data => {
          this.lightBox.directionalLight.intensity = data
          this.helperBox.directionalLightHelper.helper.update()
        })
      this.gui
        .add(this.guiParam, 'positionX', -400, 400)
        .onChange(data => {
          this.lightBox.directionalLight.position.x = data
          this.helperBox.directionalLightHelper.helper.update()
        })
      this.gui
        .add(this.guiParam, 'positionY', -400, 400)
        .onChange(data => {
          this.lightBox.directionalLight.position.y = data
          this.helperBox.directionalLightHelper.helper.update()
        })
      this.gui
        .add(this.guiParam, 'positionZ', -400, 400)
        .onChange(data => {
          this.lightBox.directionalLight.position.z = data
          this.helperBox.directionalLightHelper.helper.update()
        })
    },
    // 动画
    animation () {
    },
    // 加载场景
    updateRenderer () {
      let delta = this.clock.getDelta()
      this.orbitControls.update(delta)
      this.renderer.render(this.scene, this.camera)
      this.stats.update()

      this.animationFrame = requestAnimationFrame(this.updateRenderer)
    },
    // 清空物体缓存
    clearObjCache (obj) {
      obj.geometry.dispose()
      obj.material.dispose()
    },
    // 清空缓存
    clearCache () {
      // 渲染器缓存
      this.renderer.clear(true, true, true)
      this.renderer.dispose()
      this.renderer.forceContextLoss()
      this.renderer.domElement = null
      // 清空物体
      this.objBox.group.children.forEach(elem => {
        this.clearObjCache(elem)
      })
      // 场景缓存
      this.scene.dispose()
      // gui
      this.gui.destroy()
    },
    ...mapActions(['resetThreeTipsFun', 'resetThreeLinkFun'])
  },
  // 初始计算,信息
  created () {
    // 展示的备注
    let tips = `    旋转相机：鼠标左键
    缩放场景：鼠标滚轮
    移动相机：鼠标右键 `
    this.resetThreeTipsFun(tips)
    // github链接
    this.resetThreeLinkFun('light/ambientLight.vue')
  },
  mounted () {
    this.init()
  },
  // 清空所有绑定事件与清空画布
  beforeDestroy () {
    document.body.removeChild(document.getElementById('three-stats'))
    this.clearCache()
    this.renderer = null
    this.scene = null
    this.camera = null
    this.stats = null
    this.lightBox = null
    this.helperBox = null
    this.clock = null
    this.gui = null
    cancelAnimationFrame(this.animationFrame)
  }
}
</script>

<style lang="less" scoped>

</style>
